﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Timing;

namespace Xms.Abp.BackgroundJob;

public class InMemoryBackgroundScheduleStore : IBackgroundScheduleStore, ISingletonDependency
{
    private readonly ConcurrentDictionary<string, BackgroundScheduleInfo> _schedules;
    private readonly ConcurrentDictionary<string, BackgroundScheduleInfo> _deleteSchedules;

    protected IClock Clock { get; }

    /// <summary>
    /// Initializes a new instance of the <see cref="InMemoryBackgroundScheduleStore"/> class.
    /// </summary>
    public InMemoryBackgroundScheduleStore(IClock clock)
    {
        Clock = clock;
        _schedules = new ConcurrentDictionary<string, BackgroundScheduleInfo>();
        _deleteSchedules = new ConcurrentDictionary<string, BackgroundScheduleInfo>();
    }

    public async Task<BackgroundScheduleInfo> FindAsync(string scheduleName, CancellationToken cancellationToken = default)
    {
        return await Task.FromResult(_schedules.GetOrDefault(scheduleName));
    }

    public async Task InsertAsync(BackgroundScheduleInfo scheduleInfo, CancellationToken cancellationToken = default)
    {
        await Task.CompletedTask;
        _schedules[scheduleInfo.Name] = scheduleInfo;
    }

    public async Task<List<BackgroundScheduleInfo>> GetModifiedSchedulesAsync(DateTime lastCheckTime, CancellationToken cancellationToken = default)
    {
        return await Task.FromResult(_schedules.Values.Where(r=>r.ModificationTime >= lastCheckTime).ToList());
    }

    public async Task<List<BackgroundScheduleInfo>> GetDeletedSchedulesAsync(DateTime lastCheckTime, CancellationToken cancellationToken = default)
    {
        var list = _deleteSchedules.Values.ToList();
        _deleteSchedules.Clear();
        return await Task.FromResult(list);
    }


    public async Task<List<BackgroundScheduleInfo>> GetAllSchedulesAsync(CancellationToken cancellationToken = default)
    {
        return await Task.FromResult(_schedules.Values.ToList());
    }

    public async Task DeleteAsync(string scheduleName, CancellationToken cancellationToken = default)
    {
        if (_schedules.TryRemove(scheduleName, out var _schedule))
        {
            _schedule.ModificationTime = Clock.Now;
            _deleteSchedules[scheduleName] = _schedule;
        }

        await Task.CompletedTask;
    }

    public async Task UpdateAsync(BackgroundScheduleInfo scheduleInfo, CancellationToken cancellationToken = default)
    {
        await Task.CompletedTask;
        _schedules[scheduleInfo.Name] = scheduleInfo;
    }

    public async Task<BackgroundScheduleInfo> FindAsync(Guid id, CancellationToken cancellationToken = default)
    {
        var info = _schedules.Values.FirstOrDefault(r => r.Id == id);
        return await Task.FromResult(info);
    }
}
